package com.soap.desensitize.strategy.rreversible.symmetry;

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.*;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;

import com.soap.desensitize.encry.rreversible.symmetry.AbstractSymmetryEncry;
import com.soap.desensitize.exception.strategy.DecodeException;
import com.soap.desensitize.exception.strategy.EncodeException;

/**
 * @desc   des对称加密
 * @author QGP
 * @time   2022-04-21
 */
public class DesStrategy extends AbstractSymmetryEncry<String> {
    private static DesStrategy instance = null;

    /**
     * @desc 获得实例
     * @return
     */
    public static synchronized DesStrategy getInstance() {
        if (instance == null) {
            instance = new DesStrategy();
        }
        return instance;
    }

    /**
     * 必须需要8位 密码
     */
    private String password = "javaplus";

    /**
     * 密钥算法
     */
    private static final String ALGORITHM = "DES";

    /**
     * 加密/解密算法-工作模式-填充模式
     */
    private static final String CIPHER_ALGORITHM = "DES/CBC/PKCS5Padding";

    /**
     * 默认编码
     */
    private static final String CHARSET = "utf-8";

    /**
     * @desc 默认使用子类加密密码
     */
    private DesStrategy() {
        super.password = this.password;
    }

    /**
     * @desc  生成key
     * @param password
     * @return
     * @throws Exception
     */
    private static Key generateKey(String password) throws Exception {
        DESKeySpec dks = new DESKeySpec(password.getBytes(CHARSET));
        // 根据给定的字节数组构建一个秘钥
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
        return keyFactory.generateSecret(dks);
    }


    /**
     * @desc   DES加密字符串
     * @param password 加密密码，长度不能够小于8位
     * @param data     待加密字符串
     * @return 加密后字符串
     */
    @Override
    public String encode(String password, String data) throws EncodeException {
        if (password == null || password.length() < 8) {
            throw new RuntimeException("加密失败，key不能小于8位");
        }
        if (data == null)
            return null;
        try {
            // 调用方法构建一个秘钥
            Key secretKey = generateKey(password);
            // 1.获取加密算法工具类
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            IvParameterSpec iv = new IvParameterSpec(password.getBytes(CHARSET));
            // 2.对工具类对象进行初始化,
            // mode:加密/解密模式
            // key:对原始秘钥处理之后的秘钥
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);

            // 3.用加密工具类对象对明文进行加密
            byte[] bytes = cipher.doFinal(data.getBytes(CHARSET));

            //JDK1.8及以上可直接使用Base64，JDK1.7及以下可以使用BASE64Encoder
            return new String(Base64.getEncoder().encode(bytes));

        } catch (Exception e) {
            throw new EncodeException("加密异常");
        }
    }

    /**
     * @desc  DES解密字符串
     * @param password 解密密码，长度不能够小于8位
     * @param data     待解密字符串
     * @return 解密后内容
     */
    @Override
    public String decode(String password, String data) throws DecodeException {
        if (password == null || password.length() < 8) {
            throw new DecodeException("加密失败，key不能小于8位");
        }
        if (data == null)
            throw new DecodeException("加密数据不能为null");
        try {
            // 调用方法构建一个秘钥
            Key secretKey = generateKey(password);
            // 1.获取加密算法工具类
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            IvParameterSpec iv = new IvParameterSpec(password.getBytes(CHARSET));
            // 2.对工具类对象进行初始化,
            // mode:加密/解密模式
            // key:对原始秘钥处理之后的秘钥
            cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
            return new String(cipher.doFinal(Base64.getDecoder().decode(data.getBytes(CHARSET))), CHARSET);
        } catch (InvalidAlgorithmParameterException e) {
            throw new RuntimeException(e);
        } catch (NoSuchPaddingException e) {
            throw new RuntimeException(e);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        } catch (IllegalBlockSizeException e) {
            throw new RuntimeException(e);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        } catch (BadPaddingException e) {
            throw new RuntimeException(e);
        } catch (InvalidKeyException e) {
            throw new RuntimeException(e);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * @desc 使用默认加密密码，加密
     */
    @Override
    public String encode(String data) throws EncodeException {
        if (getPassword() != null) {
            return encode(getPassword(), data);
        }
        return encode(password, data);
    }

    /**
     * @desc 使用默认加密密码，解密
     */
    @Override
    public String decode(String data) throws DecodeException {
        if (getPassword() != null) {
            return decode(getPassword(), data);
        }
        return decode(password, data);
    }

}
